package com.example.demo.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.demo.entity.AnnualReturn;
import com.example.demo.entity.Stock;
import com.example.demo.service.IStockService;
import com.example.demo.utils.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author matt
 * @since 2024-08-02
 */
@Slf4j
@RestController
@RequestMapping("/stock")
public class StockController {
    @Autowired
    private IStockService stockService;

    // 计算固定收益
    @PostMapping("/calculateFixed")
    public Map<String, Object> calculateFixed(Double amount, Double investAmount, String code, LocalDate startDate, LocalDate endDate) {
        Map<String, Object> res = new HashMap<>();
        Double totalAmount = amount;
        Double totalInvest = 0.0;
        List<Stock> list = getStockListByDate(code, startDate, endDate);
        Stock cursorStock = list.get(0);
        List<AnnualReturn> annualReturnList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            int currentYear = list.get(i).getDate().getYear();
            if (currentYear > cursorStock.getDate().getYear()) {
                 // 获取当前年份的金额
                double pl = list.get(i - 1).getClose() / cursorStock.getClose();
                totalAmount = totalAmount * pl;
                log.debug("当前年份：{}，盈亏：{}% ，股票市值：{}", cursorStock.getDate().getYear(), String.format("%.2f",(pl - 1) * 100), String.format("%.2f",totalAmount));
                totalAmount = totalAmount + investAmount;
                totalInvest += investAmount;
                log.debug("定投：{}, 市值：{}", investAmount, String.format("%.2f",totalAmount));
                AnnualReturn annualReturn = new AnnualReturn();
                annualReturn.setYear(cursorStock.getDate().getYear());
                annualReturn.setPal((pl - 1) * 100);
                annualReturn.setInvestAmount(investAmount);
                annualReturn.setBalance(totalAmount);
                annualReturnList.add(annualReturn);
                // 移动指针
                cursorStock = list.get(i);
            }
            if (i == list.size() - 1) {
                double pl = list.get(i).getClose() / cursorStock.getClose();
                totalAmount = totalAmount * pl;
                log.debug("当前年份：{}，盈亏：{}% ，股票市值：{}", currentYear, String.format("%.2f",(pl - 1) * 100), String.format("%.2f",totalAmount));
                AnnualReturn annualReturn = new AnnualReturn();
                annualReturn.setYear(currentYear);
                annualReturn.setPal((pl - 1) * 100);
                annualReturn.setInvestAmount(0.0);
                annualReturn.setBalance(totalAmount);
                annualReturnList.add(annualReturn);
            }
        }
        LocalDate startYear = list.get(0).getDate();
        LocalDate endYear = list.get(list.size()-1).getDate();
        res.put("initialAmount", amount);
        res.put("totalAmount", totalAmount);
        res.put("totalInvest", totalInvest);
        res.put("totalProfit", CommonUtils.getTotalProfit(totalAmount, amount, totalInvest));
        res.put("totalProfitPercentage", CommonUtils.getTotalProfitPercentage(totalAmount, amount, totalInvest));
        res.put("avgYearPercentage", CommonUtils.getAvgYearPercentage(totalAmount, amount, totalInvest, startYear, endYear));
        res.put("annualReturnList", annualReturnList);
        return res;
    }

    // 计算浮动收益
    @PostMapping("/calculateFloat")
    public Map<String, Object> calculateFloat(Double amount, Double withdrawPercentage, Double cash, Double investPercentage,
                                 Double investAmount, String code, LocalDate startDate, LocalDate endDate) {
        Map<String, Object> res = new HashMap<>();
        Double totalAmount = amount;
        Double initialCash = cash;
        Double totalInvest = 0.0;
        List<AnnualReturn> annualReturnList = new ArrayList<>();
        List<Stock> list = getStockListByDate(code, startDate, endDate);
        Double cursorAmount = amount;
        Stock cursorStock = list.get(0);
        for (int i = 0; i < list.size(); i++) {
            int currentYear = list.get(i).getDate().getYear();
            if (currentYear > cursorStock.getDate().getYear()) {
                // 获取当前年份的金额
                double pl = list.get(i - 1).getClose() / cursorStock.getClose();
                totalAmount = totalAmount * pl;
                log.debug("当前年份：{}，盈亏：{}% ，股票市值：{}，现金：{}", cursorStock.getDate().getYear(), String.format("%.2f",(pl - 1) * 100), String.format("%.2f",totalAmount), String.format("%.2f",cash));

                // 再平衡
                if (list.get(i-1).getClose() > cursorStock.getClose()) {
                    // 当年盈利取出盈利一半
                    double withdrawAmount = (totalAmount - cursorAmount) * withdrawPercentage / 100;
                    if (totalAmount > withdrawAmount) {
                        totalAmount -= withdrawAmount;
                        cash += withdrawAmount;
                        log.debug("当年盈利，取出 {}% 盈利 {} 到现金", withdrawPercentage, String.format("%.2f",withdrawAmount));
                    }
                } else {
                    // 当年亏损，投入现金的百分比
                    double invest = cash * investPercentage / 100;
                    if (cash > invest) {
                        cash -= invest;
                        totalAmount += invest;
                        log.debug("当年亏损，取出 {}% 现金 {} 到股票", investPercentage, String.format("%.2f",invest));
                    }
                }

                // 定投
                totalAmount = totalAmount + investAmount;
                totalInvest += investAmount;
                log.debug("定投：{}, 市值：{}", investAmount, String.format("%.2f",totalAmount));
                AnnualReturn annualReturn = new AnnualReturn();
                annualReturn.setYear(cursorStock.getDate().getYear());
                annualReturn.setPal((pl - 1) * 100);
                annualReturn.setInvestAmount(investAmount);
                annualReturn.setBalance(totalAmount);
                annualReturn.setCash(cash);
                annualReturnList.add(annualReturn);
                // 移动指针
                cursorAmount = totalAmount;
                cursorStock = list.get(i);
            }
            if (i == list.size() - 1) {
                double pl = list.get(i).getClose() / cursorStock.getClose();
                totalAmount = totalAmount * pl;
                log.debug("当前年份：{}，盈亏：{}% ，股票市值：{}，现金：{}", currentYear, String.format("%.2f",(pl - 1) * 100), String.format("%.2f",totalAmount), String.format("%.2f",cash));
                AnnualReturn annualReturn = new AnnualReturn();
                annualReturn.setYear(currentYear);
                annualReturn.setPal((pl - 1) * 100);
                annualReturn.setInvestAmount(0.0);
                annualReturn.setBalance(totalAmount);
                annualReturn.setCash(cash);
                annualReturnList.add(annualReturn);
            }
        }

        LocalDate startYear = list.get(0).getDate();
        LocalDate endYear = list.get(list.size()-1).getDate();
        res.put("initialAmount", amount+initialCash);
        res.put("totalAmount", totalAmount+cash);
        res.put("totalInvest", totalInvest);
        res.put("totalProfit", CommonUtils.getTotalProfit(totalAmount+cash, amount+initialCash, totalInvest));
        res.put("totalProfitPercentage", CommonUtils.getTotalProfitPercentage(totalAmount+cash, amount+initialCash, totalInvest));
        res.put("avgYearPercentage", CommonUtils.getAvgYearPercentage(totalAmount+cash, amount+initialCash, totalInvest, startYear, endYear));
        res.put("annualReturnList", annualReturnList);
        return res;
    }

    @PostMapping("/getStockListByDate")
    public List<Stock> getStockListByDate(String code, LocalDate startDate, LocalDate endDate) {
        LambdaQueryWrapper<Stock> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Stock::getCode, code);
        wrapper.between(Stock::getDate, startDate, endDate);
        wrapper.orderByAsc(Stock::getDate);
        return stockService.list(wrapper);
    }


}
